<?

// Gestio d'arbres amb multiples fills

class arbre
{
	 
	 // Contingut de cada node
	 var $nom;             // nom del node
	 var $tipus;           // tipus de node (tag/cdata)
	 var $valor;           // si aplica, valor de cdata
	 var $params;          // array de parametres (si aplica)
	 var $nfills;          // comptador de fills (no caldria, pero facilita
	                       // les coses :P)	 
	 var $fills;           // array de punters als fills
	 var $pare;            // punter al pare
	 var $first;           // punter al primer fill
	 var $last;            // punter a l'ultim fill
	 var $pre;             // informacio de traduccio previa al tag
	 var $post;            // informacio de traduccio posterior al tag
	 var $endtag;
	 
	 function arbre($nom=NULL, $tipus=NULL, $valor=NULL, $params=NULL)
	 {
		  // Constructora

		  // Inicialitzem els valors del nou arbre
		  $this->nom=$nom;
		  $this->tipus=$tipus;
		  $this->valor=$valor;
		  $this->params=$params;
		  $this->fills=array();
		  $this->pare=NULL;		  		  
		  $this->nfills=0;
		  $this->first=NULL;
		  $this->last=NULL;
		  $this->pre=NULL;
		  $this->post=NULL;
		  $this->endtag=NULL;
	 }

	 
	 function printarbre($arb, $lev, $final)
	 {
		  // Printa un arbre per pantalla recursivament (DEBUG)
		  if ($arb==NULL)
			 return;
		  
		  echo("<BR>");
		  if ($lev>0)
		  {
				for ($i=0; $i<$lev; $i++)
				{
					 if ($final[$i]==0 || $final[$i]==1)
					 {
						  if ($final[$i]==1)
							 $final[$i]=2;
						  echo("|   ");
					 }
					 else
						echo("    ");
				}
				echo("<br>");
				for ($i=0; $i<$lev-1; $i++)
				{
					 if ($final[$i]<2)
						echo("|   ");
					 else
						echo("    ");
				}	
				if ($final[$i]==0 || !isset($final[$i]))
				  echo("|-- ");
				else
				  echo("'-- ");
		  }
		  echo(($arb->nom)." (".($arb->tipus)." = ".($arb->valor).")");
		  if ($arb->pare!=NULL)
			 echo(" || pare = ".($arb->pare->nom));
		  else
			 echo(" || pare NULL");
//		  echo(" || count params = ".(count($arb->params)));
		  
		  
		  for ($i=0; $i<$arb->nfills; $i++)
		  {
//				echo("<BR>Is da printarbre: nfills = ".($arb->nfills).", lev = ".$lev.", fill[".$i."] = ".($arb->fills[$i]));
				if ($i==$arb->nfills-1)
				  $final[$lev]=1;
				else
				  $final[$lev]=0;
				
				$this->printarbre($arb->fills[$i], $lev+1, $final);
		  }
//		  printarbre(($arb->fe), $lev+1);
//		  printarbre(($arb->fd), $lev+1);
	 }

	 
	 function dumpa()
	 {
		  // Escriu l'arbre per pantalla (DEBUG)
		  echo("<PRE>");
		  $this->printarbre($this, 0, array());
		  echo("</PRE>");
	 }
	 
	 function &nouTag($nom=NULL, $params=NULL)
	 {
		  return ($this->nouFill($nom, "tag", NULL, $params));
	 }
	 
	 function &nouCData($valor=NULL)
	 {
		  return ($this->nouFill(NULL, "cdata", $valor, NULL));
	 }
	 	 
	 function &nouFill($nom=NULL, $tipus=NULL, $valor=NULL, $params=NULL)
	 {
		  // Afegeix un fill a l'arbre actual (al final de la llista de fills)
		  $this->fills[]=new arbre($nom, $tipus, $valor, $params);
		  $this->fills[$this->nfills]->pare=&$this;
		  $this->last=&$this->fills[$this->nfills];
		  if ($this->nfills==0)
			 $this->first=$this->fills[$this->nfills];
		  $this->nfills++;
		  return ($this->last);
	 }

	 
	 function treuFill()
	 {
		  // Elimina l'ultim fill de la llista de fills
		  $this->nfills--;
		  unset($this->fills[$this->nfills]);
		  $this->fills=array_values($this->fills); // cal reindexar l'array
		  if ($this->nfills!=0)
			 $this->last=&$this->fills[$this->nfills-1];		  
		  else
		  {
				$this->first=NULL;
				$this->last=NULL;
		  }		  
	 }
	 
	 
	 function arb2xml($arb)
	 {
		  // Funcio recursiva de conversio a XML
		  if ($arb==NULL)
			 return "";
		  
		  if ($arb->tipus=="cdata")
			 return ($arb->valor);
		  
		  $x=new xmlgen();
		  $cdf=array();
		  $cdata="";
		  for ($i=0; $i<$arb->nfills; $i++)
		  {
				$cdf[$i]=$this->arb2xml($arb->fills[$i]);
				$cdata.=$cdf[$i];
		  }
		  $tmp=new xmlparams();
		  for ($i=0; $i<count($arb->params); $i++)
				$tmp->addParam($arb->params[$i]['nom'], $arb->params[$i]['valor']);
		  $tmp2=$tmp->getParString();
		  $x->addTag($arb->nom, $cdata, $tmp2);
//		  echo("<BR>arb2xml :: ".htmlspecialchars($x->getXML()));
		  return ($x->getXML());
	 }
	 
	 
	 function toXML()
	 {
		  // Converteix l'arbre en una cadena XML
		  $x=$this->arb2xml($this);
		  return ($x);
	 }
	 
	 
	 function &cercaFill($nom)
	 {
		  // Cerca i retorna el fill de l'arbre actual
		  // que tingui el nom indicat
		  // _1_ sol nivell tu da leet
		  for ($i=0; $i<$this->nfills; $i++)
			 if ($this->fills[$i]->nom==$nom)
				return ($this->fills[$i]);
						  
		  // no l'hem trobat
		  return NULL;
		  
	 }
	 

	 function getCdata()
	 {
		  // Retorna una cadena corresponent a tots els
		  // fills de l'arbre que siguin de tipus cdata

		  $cad="";
		  
//		  echo("<BR>nfills = ".$this->nfills);
		  for ($i=0; $i<$this->nfills; $i++)
		  {
//				echo("<BR>da tipus = ".$this->fills[$i]->tipus);
				$cad.=$this->fills[$i]->valor;
				if ($this->fills[$i]->tipus!="cdata")
				{
					 if ($this->fills[$i]->nfills>0)
					 {
						  $tmp=$this->fills[$i];
						  $cad.=$tmp->getCdata();
					 }
					 $cad.=$this->fills[$i]->endtag;
				}
		  }
		  
//		  echo("<BR>Aim da cdata = $cad");

		  // Substituim
/*		  $cad2=eregi_replace("([\\$]{2,}|[^\\$])\\$([^ \t\n\\$]+);", "\\1&\\2;", $cad);
		  while ($cad2!=$cad)
		  {
				$cad=$cad2;
				$cad2=eregi_replace("([\\$]{2,}|[^\\$])\\$([^ \\t\\n\\$]+);", "\\1&\\2;", $cad);
		  }
*/
//		  echo $cad."<br>"; 
		  $cad2=eregi_replace("[^\\\\]([^ \t\n\\{\\}]+);\\}", "&\\1;", $cad);
		  while ($cad2!=$cad)
		  {
//				echo $cad2."<br>"; 
				$cad=$cad2;
				$cad2=eregi_replace("[^\\\\]([^ \t\n\\{\\}]+);\\}", "&\\1;", $cad);
		  }

		  $cad=eregi_replace("\\\\\\{", "{", $cad);
		  $cad=eregi_replace("\\\\\\}", "}", $cad);
		  
//		  echo $cad."<br>";
		  
		  return ($cad);
	 }
}

?>
